import {
  Ref,
  ShallowRef,
  onBeforeUnmount,
  onMounted,
  ref,
  shallowRef,
} from 'vue';
import type { GeometryObject } from 'geojson';
import * as L from 'leaflet';
import 'leaflet/dist/leaflet.css';

type CurrentTile = 1 | 2 | 3;
type Tiles = [1, 2, 3];

interface UseLeafletResponse {
  /**
   * Leaflet 地图实例
   */
  map: ShallowRef<L.Map | undefined>;
  /**
   * genJSON
   */
  genJSON(json: GeometryObject, options?: L.GeoJSONOptions): void;

  /**
   * 渲染地图
   */
  renderMap(): void;

  /**
   * 新增 marker
   */
  marker(latLng: L.LatLngExpression, options?: L.MarkerOptions): L.Marker;

  /**
   * 清除 marker
   */
  cleanMarker(): void;

  toggleTileLayer(value: CurrentTile): void;

  tiles: Tiles;
  currentTile: Ref<CurrentTile>;
}

const useLeaflet = (
  elId: string,
  options: L.MapOptions,
): UseLeafletResponse => {
  const ptMap = L.tileLayer(
    `http://ebs.dev.boeyo.com/map/pt/{z}/{x}/{y}/tile.png`,
  );
  const dxMap = L.tileLayer(
    `http://ebs.dev.boeyo.com/map/dx/{z}/{x}/{y}/tile.png`,
  );
  const wxMap = L.tileLayer(
    `http://ebs.dev.boeyo.com/map/wx/{z}/{x}/{y}/tile.png`,
  );

  const markers: L.Marker[] = [];

  const tileLayerMap = new Map<CurrentTile, L.TileLayer>([
    [1, ptMap],
    [2, dxMap],
    [3, wxMap],
  ]);
  const currentTile = ref<CurrentTile>(1);
  const tiles: Tiles = [1, 2, 3];
  let map = shallowRef<L.Map | undefined>(undefined);
  const renderMap = () => {
    map.value = L.map(elId, options).setView(options.center!, 6);
  };

  onBeforeUnmount(() => {
    console.log('unmount map');
    map.value = undefined;
  });

  const genJSON = (json: GeometryObject, options: L.GeoJSONOptions) => {
    L.geoJSON(json, options).addTo(map.value!);
  };

  const marker = (
    latLng: L.LatLngExpression,
    options?: L.MarkerOptions,
  ): L.Marker => {
    const m = L.marker(latLng, options).addTo(map.value!);
    markers.push(m);
    return m;
  };

  const cleanMarker = () => {
    markers.forEach((m) => {
      map.value?.removeLayer(m);
    });
  };

  const toggleTileLayer = (value: CurrentTile) => {
    map.value?.removeLayer(tileLayerMap.get(currentTile.value)!);
    map.value?.addLayer(tileLayerMap.get(value)!);
    currentTile.value = value;
  };

  return {
    map,
    genJSON,
    renderMap,
    marker,
    cleanMarker,
    toggleTileLayer,
    tiles,
    currentTile,
  };
};

export { useLeaflet };
